Imports System
Imports ValidationFramework
Imports ValidationFramework.Reflection


Namespace NewRule
    Public Class RequiredCharacterRule
        Inherits ValueRule
        ' Methods


        ''' <summary>
        ''' Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        ''' </summary>
        ''' <remarks>To help with cloning.</remarks>
        Public Sub New()
            MyBase.New(RequiredCharacterRule._runtimeTypeHandle)
            _requiredCharacter = RequiredCharacter
        End Sub

        ''' <summary>
        ''' Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        ''' </summary>
        ''' <param name="requiredCharacter">The invalid character.</param>
        Public Sub New(ByVal requiredCharacter As Char)
            MyBase.New(RequiredCharacterRule._runtimeTypeHandle)
            _requiredCharacter = requiredCharacter
        End Sub


        ''' <summary>
        ''' Called after the <see cref="Rule"/> is added to a <see cref="RuleCollection"/>.
        ''' <see cref="Rule.ErrorMessage"/> is null.
        ''' </summary>
        ''' <returns>The error message for the <see cref="Rule"/>.</returns>
        ''' <param name="tokenizedMemberName">A user friendly representation of the 
        ''' member name.</param>
        ''' <param name="descriptorType">
        ''' If <see cref="InfoDescriptor"/> is a <see cref="PropertyDescriptor"/> then <paramref name="descriptorType"/> will be 'property'.
        ''' If <see cref="InfoDescriptor"/> is a <see cref="ParameterDescriptor"/> then <paramref name="descriptorType"/> will be 'parameter'.
        ''' </param>
        Protected Overrides Function GetComputedErrorMessage(ByVal tokenizedMemberName As _
                                                                String, ByVal descriptorType As _
                                                                String) As String
            Return String.Format("The {0} '{1}' must contain the character '{2}'", _
                                 descriptorType, tokenizedMemberName, RequiredCharacter)
        End Function


        ''' <summary>
        ''' Checks if the current <see cref="Rule"/> is equivalent to another 
        ''' <see cref="Rule"/>.
        ''' </summary>
        ''' <remarks>
        ''' Called for each <see cref="Rule"/> in <see cref="RuleCollection"/> when a new 
        ''' <see cref="Rule"/> is added. This method is only called when both the existing 
        ''' <see cref="Rule"/> and the <see cref="Rule"/> being are of the same 
        ''' <see cref="Type"/> and have the same RuleSet. So it is safe to 
        ''' directly cast <paramref name="rule"/> to the current type. All properties in 
        ''' <paramref name="rule"/> should be compared to the propeties of the current 
        ''' <see cref="Rule"/>.
        ''' </remarks>
        ''' <param name="rule">The <see cref="Rule"/> to check for equivalence.</param>
        ''' <returns><see langword="true"/> if <paramref name="rule"/> is equivalent to the 
        ''' current <see cref="Rule"/>; otherwise <see langword="false"/>.</returns>
        Public Overrides Function IsEquivalent(ByVal rule As Rule) As Boolean
            Dim requiredCharacterRule As RequiredCharacterRule = DirectCast(rule,  _
                    RequiredCharacterRule)
            Return (RequiredCharacter = requiredCharacterRule.RequiredCharacter)
        End Function

        ''' <summary>
        ''' Validate the member this <see cref="Rule"/> is applied to.
        ''' </summary>
        ''' <param name="context">An <see cref="object"/> that contains data for the 
        ''' <see cref="Rule"/> to validate. The default is null.</param>
        ''' <param name="targetMemberValue">The value of the member to validate.</param>
        Public Overrides Function Validate(ByVal targetMemberValue As Object, ByVal context As Object, ByVal infoDescriptor As InfoDescriptor) As Boolean
            If (Not targetMemberValue Is Nothing) Then
                Dim valueAsString As String = CStr(targetMemberValue)
                Return Not (valueAsString.IndexOf(RequiredCharacter) = -1)
            End If
            Return True
        End Function



        ' Properties
        ''' <summary>
        ''' Gets the required character.
        ''' </summary>
        Public ReadOnly Property RequiredCharacter() As Char
            Get
                Return _requiredCharacter
            End Get
        End Property

        ''' <summary>
        ''' Gets a <see cref="string"/> that is a business interpretation of the 
        ''' <see cref="Rule"/>.
        ''' </summary>
        Public Overrides ReadOnly Property RuleInterpretation() As String
            Get
                Return String.Format("The value must contain the character '{0}'", _
                                     RequiredCharacter)
            End Get
        End Property


        ' Fields
        Private _requiredCharacter As Char

        '' RequiredCharacterRule can only be applied to strings. So pass the 
        '' <see cref="RuntimeTypeHandle"/> for string to the base constructor.
        Private Shared _runtimeTypeHandle As RuntimeTypeHandle = GetType(String).TypeHandle
    End Class
End Namespace